package model;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import tool.Randomizer;

/**
 * A simple model of a rabbit.
 * Rabbits age, move, breed, and die.
 * 
 * @author Team X
 * @version 1
 */
public class Rabbit extends Animal
{
    // Characteristics shared by all rabbits (static fields).

    // The age at which a rabbit can start to breed.
    private static final int DEF_BREEDING_AGE = 5;
    // The age to which a rabbit can live.
    private static final int DEF_MAX_AGE = 40;
    // The likelihood of a rabbit breeding.
    private static final double DEF_BREEDING_PROBABILITY = 0.60;
    // The maximum number of births.
    private static final int DEF_MAX_LITTER_SIZE = 8;
    // A shared random number generator to control breeding.
    private static final Random rand = Randomizer.getRandom();
    
    public static int breeding_age = DEF_BREEDING_AGE;
    public static int max_age = DEF_MAX_AGE;
    public static double breeding_probability = DEF_BREEDING_PROBABILITY ;
    public static int max_litter_size = DEF_MAX_LITTER_SIZE;
    
    /**
     * Create a new rabbit. A rabbit may be created with age
     * zero (a new born) or with a random age.
     * 
     * @param randomAge If true, the rabbit will have a random age.
     * @param field The field currently occupied.
     * @param location The location within the field.
     */
    public Rabbit(boolean randomAge, Field field, Location location)
    {
        super(randomAge, field, location);
        food = 5;
    }
    
    /**
     * This is what the rabbit does most of the time - it runs 
     * around. Sometimes it will breed or die of old age.
     * @param newRabbits A list to add newly born rabbits to.
     */
    public void act(List<Animal> newRabbits)
    {
        incrementAge();
        incrementHunger();
        becomeSick();
        if(isAlive()) 
        {
        	// Breed
            giveBirth(newRabbits);
            // Search food
            findFood();
        }
    } 
    
    /**
     * This makes a rabbit search for food
     */
    public void findFood()
    {
    	//Found food?
    	boolean found = false;
    	//Squares around the rabbit
    	List<Location> locations = field.adjacentLocations(location);
    	//Look for food in all squares around the Rabbit
    	for(Iterator<Location> it = locations.iterator(); it.hasNext(); )    	
    	{
    		Location spot = it.next();
    		if(field.getObjectAt(spot) instanceof Grass)
    		{
    			int grassHeight = field.getGrassHeight(spot.getRow(), spot.getCol());
    			if(grassHeight > 0)
    			{
    				//Eat
    				food = food + grassHeight;
    				//Found food
    				found = true;
    				//Remove grass
    				field.decrementGrassHeight(spot.getRow(), spot.getCol());
    				//Set current location
    				setLocation(spot);
    			}
    		}
    	}
    	//Look for an empty location to go to
    	if(!found)
    	{
            Location newLocation = getField().freeAdjacentLocation(getLocation());
            if(newLocation != null) {
                setLocation(newLocation);
            }
            else {
                //Die of overcrowding
                setDead();
            }
    	}
    }

    /**
     * Check whether or not this rabbit is to give birth at this step.
     * New births will be made into free adjacent locations.
     * @param newRabbits A list to add newly born rabbits to.
     */
    protected void giveBirth(List<Animal> newRabbits)
    {
        // New rabbits are born into adjacent locations.
        // Get a list of adjacent free locations.
        Field field = getField();
        List<Location> free = field.getFreeAdjacentLocations(getLocation());
        int births = breed();
        for(int b = 0; b < births && free.size() > 0; b++) {
            Location loc = free.remove(0);
            Rabbit young = new Rabbit(false, field, loc);
            
            // If parent is sick, kids will have a chance to be sick too
        	if(this.sick) young.becomeSick();
            
            newRabbits.add(young);
        }
    }
        
    /**
     * Generate a number representing the number of births,
     * if it can breed.
     * @return The number of births (may be zero).
     */
    protected int breed()
    {
        int births = 0;
        if(canBreed() && rand.nextDouble() <= DEF_BREEDING_PROBABILITY) {
            births = rand.nextInt(DEF_MAX_LITTER_SIZE) + 1;
        }
        return births;
    }

    /**
     * A rabbit can breed if it has reached the breeding age.
     * @return true if the rabbit can breed, false otherwise.
     */
    private boolean canBreed()
    {
        return age >= DEF_BREEDING_AGE;
    }

	@Override
	public int getBreedingAge() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int getMaxAge() {
		return max_age;
	}

	@Override
	public double getBreedingprobability() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int getMaxLitterSize() {
		// TODO Auto-generated method stub
		return 0;
	}

	
	@Override
	public void setBreedingAge(int age) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void setMaxAge(int age) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void setBreedingprobability(double probability) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void setMaxLitterSize(int age) {
		// TODO Auto-generated method stub
		
	}
	
	/**
	 * Reset the class values to default when the simulator is resetting
	 */
	public void reset() 
	{
		breeding_age = DEF_BREEDING_AGE;
		max_age = DEF_MAX_AGE;
		breeding_probability = DEF_BREEDING_PROBABILITY;
	    max_litter_size = DEF_MAX_LITTER_SIZE;		
	}
	
	/**
	 * Reset the class values to default when the class values are changing
	 * while the simulator is running
	 */
	public static void defReset() 
	{
		breeding_age = DEF_BREEDING_AGE;
		max_age = DEF_MAX_AGE;
		breeding_probability = DEF_BREEDING_PROBABILITY;
	    max_litter_size = DEF_MAX_LITTER_SIZE;		
	}
	
	/**
	 * Change class characteristics
	 * @param itemToChange
	 * @param value
	 */
	 public static void changeCharacteristics(String itemToChange, double value) 
	    {
	    	if (itemToChange.equals("breeding_age"))
	    		breeding_age = (int)value;
	    	if (itemToChange.equals("max_age"))
	    		max_age = (int)value;
	    	if (itemToChange.equals("breeding_probability"))
	    		breeding_probability = value;
	    	if (itemToChange.equals("max_litter_size"))
	    		max_litter_size = (int)value;
	    }
	 
	 /**
	  * Get class characteristics
	  * @return Class characteristics 
	  */
	 public static int[] getCharacterInfo() 
		{
			int[] returnArray = new int[10];
			returnArray[0] = breeding_age ;
			returnArray[1] = max_age ;
			returnArray[2] = max_litter_size;
			return returnArray;		
		}

	 /**
	  * Get the probability of the breeding
	  * @return breeding_probability
	  */
	 public static double getBreedingProbability() 
		{
			return breeding_probability;
		}
}

